package edu.caltech.cs.cs141.CopilotWeb.client;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import edu.caltech.cs.cs141.CopilotWeb.shared.AbPoint;
import edu.caltech.cs.cs141.CopilotWeb.shared.ClientTripHeader;
import edu.caltech.cs.cs141.CopilotWeb.shared.Coordinate;
import edu.caltech.cs.cs141.CopilotWeb.shared.FieldVerifier;
import edu.caltech.cs.cs141.CopilotWeb.shared.TripDataClient;

// Data visualization tools
import com.google.gwt.visualization.client.AbstractDataTable;
import com.google.gwt.visualization.client.AbstractDataTable.ColumnType;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.Selection;
import com.google.gwt.visualization.client.events.SelectHandler;
import com.google.gwt.visualization.client.visualizations.corechart.AxisOptions;
import com.google.gwt.visualization.client.visualizations.corechart.Options;
import com.google.gwt.visualization.client.visualizations.corechart.BarChart;
import com.google.gwt.visualization.client.visualizations.corechart.PieChart;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.OpenEvent;
import com.google.gwt.event.logical.shared.OpenHandler;
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.Maps;
import com.google.gwt.maps.client.control.LargeMapControl;
import com.google.gwt.maps.client.geocode.DirectionQueryOptions;
import com.google.gwt.maps.client.geocode.DirectionResults;
import com.google.gwt.maps.client.geocode.Directions;
import com.google.gwt.maps.client.geocode.DirectionsCallback;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.geom.LatLngBounds;
import com.google.gwt.maps.client.overlay.Icon;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.maps.client.overlay.MarkerOptions;
import com.google.gwt.maps.client.overlay.Polyline;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.DockPanel;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.StackPanel;
import com.google.gwt.user.client.ui.TabPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

@SuppressWarnings("deprecation")
public class CopilotWeb implements EntryPoint {
	// Elements used for the page
	private VerticalPanel mainPanel = new VerticalPanel();
	private HorizontalPanel hPanel = new HorizontalPanel();
	private TabPanel tabPanel = new TabPanel();
	private ListBox userSelect = new ListBox(false);
	private HorizontalPanel dashTab = new HorizontalPanel();
	private HorizontalPanel tripTab = new HorizontalPanel();
    private VerticalPanel userInfo = new VerticalPanel();
    
    //user photo and name etc. const among all pages
    private HorizontalPanel currentUser = new HorizontalPanel();
    private Label currentUserLabel = new Label();
    final Image currentUserPhoto = new Image();
    
    //dashboard userinfo
    private DisclosurePanel scorePanel = new DisclosurePanel("Score");
    private DisclosurePanel achievePanel = new DisclosurePanel("Achievements");
    private DisclosurePanel friendsPanel = new DisclosurePanel("Friends");
    
    //dashboard
    private VerticalPanel dashInfo = new VerticalPanel();
    private DisclosurePanel notification = new DisclosurePanel("Notifications");
    private VerticalPanel mapPanel = new VerticalPanel();
    private VerticalPanel barPanel = new VerticalPanel();
	private TripInterfaceAsync tripservice = GWT.create(TripInterface.class);
	
	//Trip panel userinfo
	private Label tripList  = new Label("Trip List");
	private Label trend = new Label("Trend");
	private VerticalPanel tripUserPanel = new VerticalPanel();
	private VerticalPanel tripListPanel = new VerticalPanel();
	private VerticalPanel triptrendPanel = new VerticalPanel();
	private DeckPanel tripdeck = new DeckPanel();
	
	
	
	/* variables that need to be queries from server */
	  int avgScore = 0;
	  int bestScore = 0;
	  int recentScore = 0;
	  List<Coordinate> destList = new ArrayList<Coordinate>();
	  
	  
	  /**
	   * Entry point method.
	   */
	  public void onModuleLoad() {
		  
		//set up the layout
		String [] tablist = {"DashBoard", "My Trips", "Achievements", "Friends"};
		userSelect.addItem("Michael Wu");
		userSelect.addItem("Jeremy Davis");
		String username = userSelect.getItemText(0);
		hPanel.add(userSelect);
		mainPanel.setSpacing(20);
		    
		// load service and map api
		currentUserPhoto.setUrl("user.png");
		currentUserPhoto.setWidth("100");
		if (tripservice == null) {
			tripservice = GWT.create(TripInterface.class);
		}
		
		// Asynctask to draw map and charts
		final Runnable mapRun = new Runnable () {
			public void run() {
				final MapWidget destMap = new MapWidget();
				destMap.setSize("100%", "100%");
				LatLng center = null;
				for (int i = 0; i < destList.size(); i++) {
					double lat = destList.get(i).getLat();
					double lon = destList.get(i).getLon();
					LatLng ll = LatLng.newInstance(lat, lon);
					destMap.addOverlay(new Marker(ll));
					if (center == null) {
						center = ll;
					}
				}
				destMap.addControl(new LargeMapControl());
				destMap.setCenter(center,9);
				mapPanel.add(destMap);
			}
		};
		
		final Runnable chartRun = new Runnable () {
			public void run() {
				final BarChart barChart = new BarChart(createTable(avgScore), createOptions());
				barChart.setSize("100%", "100%");
				dashInfo.add(barChart);
			}
		};
		
	    // Set up the callback object.
	    AsyncCallback<List<ClientTripHeader>> callback = new AsyncCallback<List<ClientTripHeader>>() {
	      public void onFailure(Throwable caught) {
	        // TODO: Do something with errors.
	    	  System.out.println("failed");
	      }

	      @SuppressWarnings("unchecked")
		public void onSuccess(List<ClientTripHeader> result) {
	    	  
	    	  int[] scoreList = new int[result.size()];
	    	  
	    	  int total = 0;
	    	  long recent = 0;
	    	  Collections.sort(result);
    		  boolean recentTag = false;
    		  boolean lastweekTag = false;
	    	  for (int i = 0; i < result.size(); i++) {
	    		  // update constant needed for dashboard panel
	    		  ClientTripHeader cth = result.get(i);
	    		  double endlat = cth.getEndLat();
	    		  double endlon = cth.getEndLon();
	    		  Coordinate c = new Coordinate();
	    		  c.setLat(endlat);
	    		  c.setLon(endlon);
	    		  destList.add(c);
	    		  
	    		  int currentscore = cth.getScore();
	    		  scoreList[i] = currentscore;
	    		  total+=currentscore;
	    		  bestScore = Math.max(bestScore, currentscore);
	    		  long starttime = cth.getStart();
	    		  if (starttime > recent) {
	    			  recent = starttime;
	    			  recentScore = currentscore;
	    		  }
	    		  
	    		  //now update the triplist panel
	    		  String type = cth.getType();
	    		  
				  long id = cth.getID();
	    		  if (System.currentTimeMillis() - starttime < 7 * 24 * 3600 * 1000) {
	    			  if (recentTag == true) {
	    				  addExpandable(type, id, starttime);
	    			  } else {
	    				  Label recentweek = new Label("Previous Week");
	    				  tripListPanel.add(recentweek);
	    				  addExpandable(type, id, starttime);
	    				  recentTag = true;
	    			  }
	    		  } else {
	    			  if (lastweekTag == false && i < 20) {
	    				  Label lastweek = new Label("More than a week old");
	    				  tripListPanel.add(lastweek);
	    				  addExpandable(type, id, starttime);
	    				  lastweekTag = true;
	    			  } else if (lastweekTag == true && i < 20) {
	    				  addExpandable(type, id, starttime);	    				  
	    			  }
	    		  }	    		  
	    	  }
	    	  if (result.size() > 20) {
	    		  tripListPanel.add(new Label("more"));
	    	  }
	    	  avgScore = (int) total/result.size();
	    	  //buildScoreTable(scoreList);
	    	  Maps.loadMapsApi("", "2", false, mapRun);
	  	      VisualizationUtils.loadVisualizationApi(chartRun, BarChart.PACKAGE);
	      }
	    };
	    
	    tripservice.getTripList("Michael Wu", callback);
		
	    
	    
	    // Creating contents for each tab
	    
	    
	    // Dashboard
	    userInfo.setWidth("250");
	    userInfo.setStyleName("userinfo");
	    currentUser.add(currentUserPhoto);
	    userInfo.add(currentUser);
	    currentUserLabel.setText(username);
	    currentUser.add(currentUserLabel);	    
	    userInfo.add(scorePanel);
	    userInfo.add(achievePanel);
	    userInfo.add(friendsPanel);
	    
	    dashInfo.setSpacing(40);
	    dashInfo.add(notification);
	    mapPanel.setSize("600", "350");
	    dashInfo.add(mapPanel);
	    
	    dashTab.setSpacing(30);
	    dashTab.add(userInfo);
	    dashTab.add(dashInfo);
	    
	    // Tripinfo
	    tripUserPanel.setWidth("250");
	    tripUserPanel.setStyleName("userinfo");
	    tripUserPanel.add(currentUser);
	    tripUserPanel.add(tripList);
	    tripUserPanel.add(trend);
	    tripListPanel.setWidth("600");
	    triptrendPanel.setWidth("600");
	    tripdeck.add(tripListPanel);
	    tripdeck.add(triptrendPanel);
	    tripTab.add(tripUserPanel);
	    int tripdecknum = 0;
	    tripdeck.showWidget(tripdecknum);
	    tripdeck.setAnimationEnabled(true);
	    
	    tripTab.add(tripdeck);
	    
	    trend.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				tripdeck.showWidget(1);
		    }
			
	    	
	    });
	    
	    tripList.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				tripdeck.showWidget(0);
		    }
			
	    	
	    });
	    
	    
	    
	    
	    // Build the tab panel
	    tabPanel.setSize("1000","100%");
	    tabPanel.add(dashTab, "Dashboard");
	    tabPanel.add(tripTab, "My trips");
	    
	    // Add everything for display
	    tabPanel.selectTab(0);
	    mainPanel.add(hPanel);
	    mainPanel.add(tabPanel);
	    RootPanel.get("routeList").add(mainPanel);
	  }
	  
	  private AbstractDataTable createTable(int myscore) {
		    DataTable data = DataTable.create();
		    data.addColumn(ColumnType.STRING, "Scorer");
		    data.addColumn(ColumnType.NUMBER, "Score");
		    data.addRows(3);
		    data.setValue(0, 0, "90th Percentile");
		    data.setValue(0, 1, 95);
		    data.setValue(1, 0, "Me");
		    data.setValue(1, 1, myscore);
		    data.setValue(2, 0, "Average");
		    data.setValue(2, 1, 60);
		    return data;
		  }
	  
	  private Options createOptions() {
		    Options options = Options.create();
		    options.setWidth(600);
		    options.setHeight(240);
		    AxisOptions ao = AxisOptions.create();
		    ao.setMinValue(0.0);
		    options.setHAxisOptions(ao);
		    options.setTitle("My Score Comparison");
		    return options;
		  }
	  
	  private String getDay(long time) {
		  int day = 24 * 3600 * 1000;
		  if (time/day < 1) {
			  return "Today";
		  } else if (time/day < 2) {
			  return "Yesterday";
		  } else if (time/day < 8) {
			  int intDay = (int) (time/day);
			  return intDay + " days ago";
		  } else {
			  return ">7 days";
		  }
	  }
	  
	  
	  private void addExpandable(String type, final long id, long starttime) {
		  final DisclosurePanel dp = new DisclosurePanel();
		  dp.setWidth("600");
		  Grid g = new Grid(1,2);
		  g.setText(0,0, getDay(System.currentTimeMillis() - starttime));
		  g.setSize("100%", "100%");
		  g.setText(0, 1, type);
		  setGrid(g);
		  dp.setHeader(g);
		  dp.addOpenHandler(new OpenHandler<DisclosurePanel>() {
			public void onOpen(OpenEvent<DisclosurePanel> event) {
				final VerticalPanel mappanel = new VerticalPanel();
				mappanel.setSize("600", "400");
				
				AsyncCallback<TripDataClient> callback = new AsyncCallback<TripDataClient>() {

					public void onFailure(Throwable caught) {
						System.out.println("didn't get data");
					}

					public void onSuccess(final TripDataClient result) {
						Maps.loadMapsApi("", "2", false, new Runnable(){
							public void run() {	
								mapAdd(result, mappanel, dp);
							}});
					}  
				  };
				  
				  tripservice.getTrip(id, callback);
			}			  
		  });
		  tripListPanel.add(dp);
	  }
	  
	  private LatLng CtoL(Coordinate c) {
		  double lon = c.getLon();
		  double lat = c.getLat();
		  LatLng ll = LatLng.newInstance(lat, lon);
		  return ll;
	  }
	  
	  private void mapAdd(TripDataClient tc, VerticalPanel vp, DisclosurePanel dp) {
		  final MapWidget map = new MapWidget();
		  map.setSize("100%", "100%");
		  int numPoint = tc.getGData().size();
		  LatLng[] traj = new LatLng[numPoint];
		  for (int i = 0; i < numPoint; i++) {
			  traj[i] = CtoL(tc.getGData().get(i));
			  
		  }
		  if (tc.getAData() != null) {
		  for (int i = 0; i < tc.getAData().size(); i++) {
			  AbPoint ap = tc.getAData().get(i);
			  double lon = ap.getLon();
			  double lat = ap.getLat();
			  LatLng point = LatLng.newInstance(lat, lon);
			  Marker m = null;
			  if (ap.getSeverity() == 0) {
				  m = new Marker(point, getMarkerOption("Blue"));
				  System.out.println("possible");
			  } else if (ap.getSeverity() == 1) {
				  m = new Marker(point, getMarkerOption("Purple"));
			  } else {
				  m = new Marker(point, getMarkerOption("Orange"));
			  }
			  if (m != null) {
				  map.addOverlay(m);
			  }
			  
		  }
		  }
		  Polyline mypoly = new Polyline(traj);
		  LatLngBounds b = mypoly.getBounds();
		  map.addOverlay(mypoly);
		  map.addControl(new LargeMapControl());
		  map.setCenter(b.getCenter(), 11);
		  vp.add(map);
		  dp.add(vp);
	  }
	  
	  private MarkerOptions getMarkerOption(String color) {
		  Icon i = Icon.DEFAULT_ICON;
		  String url = "DrawingPin1_" + color + ".png";
		  i.setImageURL(url);
		  MarkerOptions op = MarkerOptions.newInstance(i);
		  return op;
	  }
	  
	  private void setGrid(Grid grid) {
		  for (int i = 0; i < grid.getRowCount(); i++) {
	            for (int j = 0; j < grid.getCellCount(i); j++) {
	                if ((j % 2) == 0) {
	                    grid.getCellFormatter().setStyleName(i, j, "tableCell-even");
	                } else {
	                    grid.getCellFormatter().setStyleName(i, j, "tableCell-odd");
	                }
	            }
	        }
	  }
	  

	  
}

